﻿#include "WorldGenerator.h"

#include "App/Game.h"
#include "World/World.h"
#include "World/BlockRegistry.h"

WorldGenerator::WorldGenerator(int seed)
    : m_seed(seed)
{
  m_noise.SetSeed(m_seed);                                     // 设置种子
  m_noise.SetFractalOctaves(5);                                // 设置细节层次
  m_noise.SetFractalLacunarity(1.75f);                         // 设置不均匀度
  m_noise.SetNoiseType(FastNoiseLite::NoiseType_OpenSimplex2); // 设置噪声类型
  m_noise.SetFractalType(FastNoiseLite::FractalType_FBm);      // 设置分形类型
}

void WorldGenerator::GenerateChunk(const Ref<Chunk> &chunkRef)
{
  const auto level = Game::GetInstance().GetLevel();
  if (level == nullptr)
    return;

  LOG_TRACE("Generating chunk: ({}, {})", chunkRef->GetPosition().x, chunkRef->GetPosition().y);

  Chunk &chunk = *chunkRef;

  glm::ivec2 worldPosition = chunk.GetPosition();
  glm::vec2 position = worldPosition;

  auto reg = level->GetBlockRegistry();

  const auto bedrock = reg->GetBlockID("bedrock");

  for (int32_t x = 0; x < Chunk::HorizontalSize; x++)
  {
    for (int32_t z = 0; z < Chunk::HorizontalSize; z++)
    {
      float noiseX = (position.x + static_cast<float>(x));
      float noiseY = (position.y + static_cast<float>(z));
      float noiseValue = m_noise.GetNoise(noiseX, noiseY) / 2.0f + 0.5f;
      int32_t height = 45 + static_cast<int32_t>(noiseValue * 45);

      for (int32_t y = 0; y < height; y++)
      {
        int32_t dy = height - y;
        std::string blockToPlace = "stone";

        if (dy == 1)
        {
          if (y <= 64 && y >= 63)
          {
            blockToPlace = "sand";
          }
          else if (y < 63)
          {
            blockToPlace = "stone";
          }
          else
          {
            blockToPlace = "grass_block";
          }
        }
        else if (dy < 5)
        {
          if (y < 64)
          {
            blockToPlace = "stone";
          }
          else
          {
            blockToPlace = "dirt";
          }
        }
        auto id = reg->GetBlockID(blockToPlace);
        chunk.PlaceBlock({x, y, z}, {id});
      }

      for (int32_t y = 64; y >= height; y--)
      {
        auto waterId = reg->GetBlockID("water");
        chunk.PlaceBlock({x, y, z}, {waterId});
      }
      chunk.PlaceBlock({x, 0, z}, {bedrock});
    }
  }
}

void WorldGenerator::SetSeed(int seed)
{
  m_seed = seed;
  m_noise.SetSeed(m_seed);
}